#include "scheduler.h"

bool Scheduler::empty() { return runqueue.empty() && expiredqueue.empty(); }

int Scheduler::get_quantum() { return quantum; }

void FCFS::add_process(Process *proc) {
  runqueue.insert(runqueue.begin(), proc);
}

Process *FCFS::get_next_process() {
  Process *proc_i = runqueue.back();
  runqueue.pop_back();
  return proc_i;
}

void LCFS::add_process(Process *proc) {
  // Add at end
  runqueue.push_back(proc);
}

// Definitions for the LCFS class
Process *LCFS::get_next_process() {
  // Get from end too
  Process *proc_i = runqueue.back();
  runqueue.pop_back();
  return proc_i;
}

Process *PRIO::get_next_process() {
  if (runqueue.empty()) {
    runqueue = expiredqueue;
    expiredqueue.clear();
  }

  Process *proc_i = runqueue.back();
  runqueue.pop_back();
  return proc_i;
}

bool PRIO::goes_after(Process *p1, Process *p2) {
  int prio1 = p1->dynamic_priority;
  int prio2 = p2->dynamic_priority;

  if (prio1 > prio2) {
    return true;
  } else if (prio1 < prio2) {
    return false;
  } else {
    return false;
  }
}

void PRIO::add_process(Process *proc) {
  if (proc->dynamic_reset) {
    proc->dynamic_reset = false;
    add_expired(proc);

  } else {
    add_active(proc);
  }
}

void PRIO::add_active(Process *proc) {
  auto position = runqueue.end();

  if (runqueue.empty()) {
    runqueue.push_back(proc);
  } else {

    for (auto it = runqueue.begin(); it != runqueue.end(); ++it) {
      if (!goes_after(proc, *it)) {
        position = it;
        break;
      }
    }

    runqueue.insert(position, proc);
  }
}

void PRIO::add_expired(Process *proc) {
  auto position = expiredqueue.end();

  if (expiredqueue.empty()) {
    expiredqueue.push_back(proc);
  } else {

    for (auto it = expiredqueue.begin(); it != expiredqueue.end(); ++it) {
      if (!goes_after(proc, *it)) {
        position = it;
        break;
      }
    }

    expiredqueue.insert(position, proc);
  }
}

bool PRIO::not_empty() { return !runqueue.empty() || !expiredqueue.empty(); }

// void SJF::add_process(Process *proc) {

//   auto position = runqueue.end();

//   if (runqueue.empty()) {
//     runqueue.push_back(proc);
//   } else {

//     for (std::vector<Process *>::iterator it = runqueue.begin();
//          it != runqueue.end(); ++it) {
//       if (!goes_after(proc, *it)) {
//         position = it;
//         break;
//       }
//     }

//     runqueue.insert(position, proc);
//   }
// }

// bool SJF::goes_after(Process *p1, Process *p2) {
//   int remaining1 = p1->get_total_time() - p1->get_time_running();
//   int remaining2 = p2->get_total_time() - p2->get_time_running();

//   if (remaining2 > remaining1) {
//     return true;
//   } else if (remaining2 < remaining1) {
//     return false;
//   } else {
//     return false;
//   }
// }

// Process *SJF::get_next_process() {
//   Process *proc_i = runqueue.back();
//   runqueue.pop_back();
//   return proc_i;
// }
